#ifndef COMMON_BASEMATH_H
#define COMMON_BASEMATH_H

#include "Base.h"

template<typename Vec3Type>
inline auto dot(const Vec3Type &v1, const Vec3Type &v2) {
    return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
}

template<typename Vec3Type>
inline auto cross(const Vec3Type &v1, const Vec3Type &v2) {
    return Vec3Type(v1[1] * v2[2] - v1[2] * v2[1],
                    v1[2] * v2[0] - v1[0] * v2[2],
                    v1[0] * v2[1] - v1[1] * v2[0]);
}

template<typename Vec3Type>
inline auto length(const Vec3Type &v) {
    return glm::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
}

template<typename Vec3Type>
inline auto length2(const Vec3Type &v) {
    return v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
}

template<typename Vec3Type>
inline auto norm(const Vec3Type &v) {
    Vec3Type n = v;
    auto len = glm::sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
    if (len > fEpsilon) {
        n[0] /= len;
        n[1] /= len;
        n[2] /= len;
    }
    return n;
}

template<typename Vec3Type>
inline auto normalize(Vec3Type &v) {
    auto len = glm::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    if (len > fEpsilon) {
        v[0] /= len;
        v[1] /= len;
        v[2] /= len;
    }
    return len;
}

template<typename Vec3ArrayType, typename Vec3Type>
void compute_bounding_box(const Vec3ArrayType &X, Vec3Type &maxCorner, Vec3Type &minCorner) {
    if (X.empty())
        throw Exception("empty array!");

    maxCorner = X[0];
    minCorner = X[0];
    for (const auto &x : X) {
        maxCorner = glm::max(maxCorner, x);
        minCorner = glm::min(maxCorner, x);
    }
}


#endif // COMMON_BASEMATH_H
